<?php

/**
 * Description of dx600a
 *
 * @author Christoph Vieth <mail@christoph-vieth.de>
 */
define('DX_STAT_INIT', 0);
define('DX_STAT_ERROR', 2);
define('DX_STAT_READY', 3);
define('DX_STAT_CONNECTING', 6);
define('DX_STAT_CONNECTED', 7);
define('DX_STAT_WORKING', 8);

define('DX_DEF_ADRESS', '192.168.120.235');
define('DX_DEF_OBEX_PORT', '650');
define('DX_DEF_PIN', '0000');

define('DX_DBG_LOG', true);
define('DX_DBG_ECHO', false);

class dx600a {

    /**
     * Current status of the Object
     *  
     * @var int $status
     */
    private $status;

    /**
     * IP adress of your DX600A
     * 
     * @var string $adress
     */
    private $address;

    /**
     * TCP port of your DX600A
     * 
     * @var int $port
     */
    private $port;
    private $socket;
    private $pin;

    /**
     * Log buffer
     * @var array logBuffer
     */
    private $logBuffer;

    public function __construct() {
        $this->status = DX_STAT_INIT;

        // Initialize Object
        $this->logBuffer = array();
        $this->address = DX_DEF_ADRESS;
        $this->port = DX_DEF_OBEX_PORT;
        $this->pin = DX_DEF_PIN;

        // Object is ready
        $this->status = DX_STAT_READY;
    }

    public function __destruct() {
        $this->obexDisconnect();
    }

    /**
     * Retuns the current Status of the Object
     * @return int
     */
    public function getStatus() {
        if (($this->status == DX_STAT_CONNECTED)) {
            
        } else
            return $this->status;
    }

    /**
     * Writes given message to message buffer
     * @param string $message
     * @return bool 
     */
    private function log($message) {
        if (DX_DBG_LOG) {
            $message .= "\n";
            array_push($this->logBuffer, $message);
            if (DX_DBG_ECHO) {
                echo $message;
            }
            return true;
        } else
            return false;
    }

    /**
     * Dumps log buffer
     * @return string
     */
    public function dumpLog() {
        $output = '';
        foreach ($this->logBuffer as $logNo => $logMessage) {
            $output .= "$logNo - $logMessage";
        }
        $this->logBuffer = array();
        return $output;
    }

    /**
     * Returns log buffer
     * @return array
     */
    public function getLog() {
        return $this->logBuffer;
    }

    public function obexConnect() {
        switch ($this->status) {
            case DX_STAT_CONNECTED:
                $this->log('Object already connected! -> true');
                return true;
                break;
            case DX_STAT_CONNECTING:
                $this->log('Object already connecting! -> false');
                return true;
                break;
            case DX_STAT_INIT:
                $this->log('Cannot Connect! Status not Ready! -> false');
                return false;
                break;
            case DX_STAT_READY:

                /* Set Status to Connecting */
                $this->status = DX_STAT_CONNECTING;

                /* Create a TCP/IP socket. */
                $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                if ($this->socket === false) {
                    $this->log('socket_create() failed: reason: ' . socket_strerror(socket_last_error()));
                } else {
                    $this->log('socket successfully created.');
                }

                $this->log("Attempting to connect to '$this->address' on port '$this->port'...");
                $result = socket_connect($this->socket, $this->address, $this->port);
                if ($result === false) {
                    $this->log("socket_connect() failed.\nReason: ($result) " . socket_strerror(socket_last_error($this->socket)) . "\n");
                } else {
                    $this->log("successfully connected to $this->address.\n");
                }

                while (($this->status != DX_STAT_CONNECTED) && ($this->status != DX_STAT_ERROR)) {
                    $input = socket_read($this->socket, 2048);
                    $this->log("Reciving: $input");
                    switch ($input) {
                        case "Enter PIN>\n":
                            $output = $this->pin . "\r\n";
                            socket_write($this->socket, $output, strlen($output));
                            $this->log("Sending PIN: $output");
                            break;
                        case "BAD PIN\n":
                            socket_close($this->socket);
                            $this->log("Wrong Pin. Closing socket...");
                            $this->status = DX_STAT_ERROR;
                            return false;
                            break;
                        case "BUSY\n":
                            socket_close($this->socket);
                            $this->log("Device is busy. Closing socket...");
                            $this->status = DX_STAT_ERROR;
                            return false;
                            break;
                        case "PIN OK\n":
                            $this->status = DX_STAT_CONNECTED;
                            $this->obexInit();
                            return true;
                            break;
                        default:
                            $this->log('Unexpected answer!');
                            break;
                    }
                }

                die("This part should never get executed!");
        }
    }

    public function obexDisconnect() {
        if ($this->socket >= DX_STAT_CONNECTING) {
            socket_close($this->socket);
            $this->log("Closing socket...");
            $this->status = DX_STAT_INIT;
        }
        return true;
    }

    /**
     * Send a OBEX Command. The command will be terminated with "\r\n" and send to the device.
     * @param string $command OBEX Command to send
     * @return bool
     */
    private function obexSend($command) {
        if ((is_string($command)) && (($this->status == DX_STAT_CONNECTED) || ($this->status == DX_STAT_CONNECTING))) {
            $temp_status = $this->status;
            $this->status = DX_STAT_WORKING;
            $output = $command . "\r\n";
            socket_write($this->socket, $output, strlen($output));
            $this->log("Sending: $output");
            $this->status = $temp_status;
            return true;
        } else {
            $this->log('Cannot Send. No command or not connecting or connected!');
            return false;
        }
    }

    /**
     * Receve a message from OBEX connection
     * @return string
     */
    private function obexRecive() {
        if ((($this->status == DX_STAT_CONNECTED) || ($this->status == DX_STAT_CONNECTING))) {
            $temp_status = $this->status;
            $this->status = DX_STAT_WORKING;
            $input = socket_read($this->socket, 2048);
            $this->log("Reciving: $input");
            $this->status = $temp_status;
            return $input;
        } else {
            $this->log("Cannot Recive. Not connecting or connected!");
            return false;
        }
    }

    /**
     * Reinitialization of the AT-Command-Unit
     * @return bool
     */
    public function obexInit() {
        if ($this->status == DX_STAT_CONNECTED) {
            $this->obexSend('ATZ');
            sleep(1);
            $this->obexRecive();
            return true;
        } else {
            $this->log("Cannot Init. Not connected!");
            return false;
        }
    }

    /**
     * Query of the serial number 
     * @return bool
     */
    public function obexGetSerial() {
        if ($this->status == DX_STAT_CONNECTED) {
            $this->obexSend('AT+CGSN');
            sleep(1);
            $recived = $this->obexRecive();
            $recived = explode("\r\n", $recived);
            $this->log("Serial number: $recived[1]");
            return $recived[1];
        } else {
            $this->log("Cannot get Serial. Not connected!");
            return false;
        }
    }

    /**
     * Query of the product name
     * @return bool
     */
    public function obexGetPrdName() {
        if ($this->status == DX_STAT_CONNECTED) {
            $this->obexSend('AT^WPPN');
            sleep(1);
            $recived = $this->obexRecive();
            $recived = explode("\r\n", $recived);
            $this->log("Product Name: $recived[1]");
            return $recived[1];
        } else {
            $this->log("Cannot get Product Name. Not connected!");
            return false;
        }
    }

    /**
     * Query of SW version (41=Variant, 62=SW-Version) 
     * @return bool
     */
    public function obexGetSwVer() {
        if ($this->status == DX_STAT_CONNECTED) {
            $this->obexSend('AT+CGMR');
            sleep(1);
            $recived = $this->obexRecive();
            $recived = explode("\r\n", $recived);
            $this->log("Software Version: $recived[1]");
            return $recived[1];
        } else {
            $this->log("Cannot get Software Version. Not connected!");
            return false;
        }
    }

    /**
     * Query of the phone name
     * @return bool
     */
    public function obexGetPhoneName() {
        if ($this->status == DX_STAT_CONNECTED) {
            $this->obexSend('AT^SHSN?');
            sleep(1);
            $recived = $this->obexRecive();
            $recived = explode("\r\n", $recived);
            $this->log("Phone Name: $recived[1]");
            return $recived[1];
        } else {
            $this->log("Cannot get Phone Name. Not connected!");
            return false;
        }
    }

    /**
     * Query of the area codes 
     * @return bool
     */
    public function obexGetAreaCodes() {
        if ($this->status == DX_STAT_CONNECTED) {
            $this->obexSend('AT^SACO? ');
            sleep(1);
            $recived = $this->obexRecive();
            $recived = explode("\r\n", $recived);
            $this->log("Area Codes: $recived[1]");
            return $recived[1];
        } else {
            $this->log("Cannot get Area Code. Not connected!");
            return false;
        }
    }

    /**
     * Initiation of external call
     * @param int $number
     * @return bool
     */
    public function obexDial($number) {
        if ((is_numeric($number)) && ($this->status == DX_STAT_CONNECTED)) {
            $this->obexSend('ATD ' . $number);
            sleep(1);
            $this->obexRecive();
            sleep(1);
            $this->obexRecive();
            sleep(1);
            $this->obexRecive();
        } else {
            $this->log("Cannot Dial. No number or not connected!");
            return false;
        }
    }

}

?>
